﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lidgren.Network;
using System.Threading;
using Networking.Packets;
using Lidgren.Network.Xna;
using Microsoft.Xna.Framework;

namespace Networking
{
    /// <summary>
        /// Game server which simply broadcasts all packets to all users
        /// Modelled after Lidgren example project
        /// </summary>
    public class SimpleGameServer
    {
        NetServer server;
        bool NewPlayer = false;


        //Queue for position data
        List<LocationPacket> _LocationQueue = new List<LocationPacket>(5);
        List<PlayerInfoPacket> _PlayerQueue = new List<PlayerInfoPacket>(5);
        

        public SimpleGameServer()
        {
#if DEBUG
            Console.WriteLine("*** Server Starting in Debug Mode ***");
#endif

            NetPeerConfiguration config = new NetPeerConfiguration("magicarena");
            config.MaximumConnections = 200;

            config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
            config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
            config.Port = 14242;

            // create and start server
            server = new NetServer(config);
            
        }

        public void Start()
        {
            server.Start();
        }
        public void Close()
        {
            server.Shutdown("app exiting");
        }

        public void RunOnce()
        {
			NetIncomingMessage msg;
			while ((msg = server.ReadMessage()) != null)
			{
				switch (msg.MessageType)
				{
					case NetIncomingMessageType.DiscoveryRequest:
						// Server received a discovery request from a client; send a discovery response (with no extra data attached)
						server.SendDiscoveryResponse(null, msg.SenderEndpoint);
						break;
                    case NetIncomingMessageType.ConnectionApproval:
#if DEBUG               
                        //Console.WriteLine("Incoming LOGIN");
#endif
                        msg.SenderConnection.Approve();
                        break;
					case NetIncomingMessageType.VerboseDebugMessage:
					case NetIncomingMessageType.DebugMessage:
					case NetIncomingMessageType.WarningMessage:
					case NetIncomingMessageType.ErrorMessage:
						//
						// Just print diagnostic messages to console
						//
#if DEBUG
						Console.WriteLine(msg.ReadString());
#endif
						break;
					case NetIncomingMessageType.StatusChanged:
						NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();
						if (status == NetConnectionStatus.Connected)
						{
							//
							// A new player just connected!
							//
#if DEBUG
							Console.WriteLine(NetUtility.ToHexString(msg.SenderConnection.RemoteUniqueIdentifier) + " connected!");
#endif
                        }

						break;
					case NetIncomingMessageType.Data:
						//
						// The client sent input to the server
						//
                        UInt64 tag = (UInt64) msg.ReadInt64();
                        switch (tag)
                        {
                            case LocationPacket.TAG:
                                LocationPacket loc = new LocationPacket();
                                LocationPacket.ParseMessage(msg, ref loc);
                                loc.SenderId = (UInt64)msg.SenderConnection.RemoteUniqueIdentifier;
                                _LocationQueue.Add(loc);
#if DEBUG
                                //Console.WriteLine(String.Format("Server received LocationPacket: ({0},{1})", loc.PlayerID, loc.Location));
#endif
                                break;
                            case PlayerInfoPacket.TAG:
                                PlayerInfoPacket info = new PlayerInfoPacket();
                                PlayerInfoPacket.ParseMessage(msg, ref info);
                                info.SenderId = (UInt64)msg.SenderConnection.RemoteUniqueIdentifier;
#if DEBUG
                                Console.WriteLine(String.Format("Server received PlayerInfoPacket: ({0},{1})", info.PlayerId, info.DisplayName));
#endif
                                _PlayerQueue.Add(info);
                                NewPlayer = true;
                                break;
                        }
						break;
				}

				// If a new player joined, send updated player list to all
                if (NewPlayer)
                {
                    foreach (PlayerInfoPacket pack in _PlayerQueue)
                    {
                        NetOutgoingMessage om = server.CreateMessage();
                        PlayerInfoPacket.BuildOutputMessage(ref om, pack);

                        server.SendToAll(om, NetDeliveryMethod.ReliableUnordered);

                    }
                    NewPlayer = false;
                }
                

				// Yes, it's time to send position updates
                foreach (LocationPacket pack in _LocationQueue)
                {
                    NetOutgoingMessage om = server.CreateMessage();
                    LocationPacket.BuildOutputMessage(ref om, pack);
                    server.SendToAll(om, NetDeliveryMethod.Unreliable);
                }
                _LocationQueue.Clear();
				
					
			}
			
		}
        
    }
}
